package com.mattgarner.jaddas.node.index;

import com.mattgarner.jaddas.node.LocalDataProvider;
import com.sleepycat.je.Database;
import com.sleepycat.je.LockMode;

public class BitmapIndex {

	private LocalDataProvider dataProvider;
	private String dataStore;
	private String dataName;
	private String columnName;
	private String indexName;
	private int rowCount;
	
	private final String INDEX_KEY_STRING_ENCODING = "UTF-8";
	
	private Database columnIndexData;
	
	public BitmapIndex(LocalDataProvider dataProvider, String dataStore, String dataName, String columnName, int rowCount) throws IndexException {
		
		if((dataProvider == null) || (dataStore == null) || (dataName == null) || (columnName == null)) {
			throw new IndexException("BitmapIndex: Invalid arguments.");
		}
		
		this.dataProvider = dataProvider;
		this.dataStore = dataStore;
		this.dataName = dataName;
		this.columnName = columnName;
		this.indexName = dataName + "_" + columnName;
		this.rowCount = rowCount;
		
		dataProvider = LocalDataProvider.getInstance();
		columnIndexData = dataProvider.openDatabase(dataStore, columnName, true);
	}
	
	public final void clearIndex() throws IndexException {
		try {
			dataProvider.removeAll(columnIndexData);
		} catch (Exception e) {
			throw new IndexException("clearIndex: " + e.getMessage());
		}
	}
	
	public final void addValueToIndex(String value, int position) throws IndexException {
		try {
			byte[] valueKey = value.getBytes(INDEX_KEY_STRING_ENCODING);
			byte[] bitmap = dataProvider.getBytes(columnIndexData, valueKey, LockMode.RMW);
			BitmapIndexColumn bitmapIndexCol = null;
			if(bitmap == null) {
				bitmapIndexCol = new BitmapIndexColumn(rowCount);
			} else {
				bitmapIndexCol = new BitmapIndexColumn(bitmap);
			}
			
			bitmapIndexCol.setBit(position, true);
			
			dataProvider.put(columnIndexData, valueKey, bitmapIndexCol.getBitmap());
		} catch (Exception e) {
			throw new IndexException("addValueToIndex: " + e.getMessage());
		}
	}
	
		
	
	public final BitmapIndexColumn getBitmapByValue(String value) throws IndexException {
		try {
			byte[] valueKey = value.getBytes(INDEX_KEY_STRING_ENCODING);
			byte[] bitmap = dataProvider.getBytes(columnIndexData, valueKey, LockMode.DEFAULT);
			BitmapIndexColumn bitmapIndexCol = null;
			if(bitmap != null) {
				bitmapIndexCol = new BitmapIndexColumn(bitmap);
			}
			
			return bitmapIndexCol;
			
		} catch (Exception e) {
			throw new IndexException("getBitmapByValue: " + e.getMessage());
		}
	}
	
	public final BitmapIndexColumn union(BitmapIndexColumn colA, BitmapIndexColumn colB) throws IndexException {
		
		// check for parity
		if(colA.getBitmap().length != colB.getBitmap().length) {
			throw new IndexException("BitmapIndex.union: Index length mismatch.");
		}
		
		int bitmapSize = colA.getBitmap().length; 
		byte[] unionBitmap = new byte[bitmapSize];
		
		for(int a=0; a<bitmapSize; a++) {
			unionBitmap[a] = (byte)(colA.getBitmap()[a] | colB.getBitmap()[a]); 
		}
		
		return new BitmapIndexColumn(unionBitmap);
	}
	
	public final BitmapIndexColumn intersection(BitmapIndexColumn colA, BitmapIndexColumn colB) throws IndexException {
		
		// check for parity
		if(colA.getBitmap().length != colB.getBitmap().length) {
			throw new IndexException("BitmapIndex.intersection: Index length mismatch.");
		}
		
		int bitmapSize = colA.getBitmap().length; 
		byte[] unionBitmap = new byte[bitmapSize];
		
		for(int a=0; a<bitmapSize; a++) {
			unionBitmap[a] = (byte)(colA.getBitmap()[a] & colB.getBitmap()[a]); 
		}
		
		return new BitmapIndexColumn(unionBitmap);
	}
}
